package gui;

import io.Archivo;
import io.Carpeta;
import io.Cliente;
import io.Identificable;
import io.ItemBusqueda;
import io.servicios.InterfazServiciosServidor;
import io.servicios.ServiciosServidorException;
import java.io.File;
import java.io.IOException;
import java.rmi.RemoteException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.concurrent.Semaphore;
import javax.swing.JOptionPane;
import javax.swing.JTree;
import javax.swing.filechooser.FileFilter;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreePath;
import logica.ActualizacionArbolListener;
import logica.Nucleo;

/**
 *
 * @author Mariano Zapata
 */
public class PanelArbolControlador implements ActualizacionArbolListener {

    private JTree arbol;
    private Nucleo nucleo;
    private PanelArchivosAbiertosControlador paac;
    private PanelPestaniasControlador ppc;
    private Ventana ventana;
    private DefaultMutableTreeNode raiz;
    private Semaphore semaforo;
    private ModificadorArbol modificadorArbol;
    private Carpeta padreViejo;
    private Object elementoPegar;
    private int operacion;
    private boolean bloquearAlExpandir;

    private static final int COPIAR= 0;
    private static final int CORTAR= 1;

    public PanelArbolControlador(JTree arbol)
    {
        this.arbol= arbol;
        nucleo= null;
        paac= null;
        ppc= null;
        ventana= null;
        padreViejo= null;
        elementoPegar= null;
        operacion= -1;
        bloquearAlExpandir= true;
        arbol.setExpandsSelectedPaths(true);
        semaforo= new Semaphore(1, true);
        ArrayList<Long> rutaDirectorio= new ArrayList<Long>();
        rutaDirectorio.add(new Long(1));
        Carpeta directorio= new Carpeta(rutaDirectorio);
        directorio.setNombre("Directorio");
        directorio.setEsExpediente(false);
        raiz= new DefaultMutableTreeNode(directorio); //PARA NO GUARDAR EN EL ÁRBOL EL DIRECTORIO EXPANDIDO.
        DefaultTreeModel modeloArbol= new DefaultTreeModel(raiz);
        arbol.setModel(modeloArbol);
        modificadorArbol= new ModificadorArbol(modeloArbol);
    }

    /**
     * Se debe llamar después de haber seteado el núcleo, el controlador de archivos abiertos, el controlador de
     * pestanias y la ventana.
     */
    public void iniciar() throws RemoteException
    {
        Carpeta raizExpandida= nucleo.expandirCarpeta((Carpeta) raiz.getUserObject());
        if (!raizExpandida.getHijosCarpeta().isEmpty() || !raizExpandida.getHijosCliente().isEmpty() ||
                !raizExpandida.getHijosArchivo().isEmpty())
            modificadorArbol.agregarNodoVacio(raiz);
        nucleo.agregarActualizacionArbolListener(this);
    }

    public void setNucleo(Nucleo nucleo) {
        this.nucleo= nucleo;
    }

    public void setPanelArchivosAbiertosControlador(PanelArchivosAbiertosControlador paac) {
        this.paac= paac;
    }

    public void setPanelPestaniasControlador(PanelPestaniasControlador ppc) {
        this.ppc= ppc;
    }

    public void setVentana(Ventana ventana) {
        this.ventana= ventana;
    }

    public void colapsarCarpeta(DefaultMutableTreeNode nodoColapsar)
    {
        try {
            semaforo.acquire();
            nucleo.setSistemaOcupado();
            modificadorArbol.vaciarNodo(nodoColapsar);
            modificadorArbol.agregarNodoVacio(nodoColapsar);
            semaforo.release();
            nucleo.setSistemaLibre();
        } catch (InterruptedException ex) {ventana.errorGrave(ex.getMessage());}
    }

    public void expandirCarpeta(DefaultMutableTreeNode nodoExpandir)
    {
        Carpeta carpetaExpandir= null;
        try {
            if (bloquearAlExpandir)
            {
                semaforo.acquire();
                nucleo.setSistemaOcupado();
            }
            carpetaExpandir= (Carpeta) nodoExpandir.getUserObject();
            Carpeta carpetaExpandida= nucleo.expandirCarpeta(carpetaExpandir);
            modificadorArbol.cargarNodo(nodoExpandir, carpetaExpandida);
            if (bloquearAlExpandir)
            {
                semaforo.release();
                nucleo.setSistemaLibre();
            }
        } catch (RemoteException ex) {nucleo.setSistemaLibre();
                                      if (carpetaExpandir.esExpediente())
                                          this.manejarExcepcion(ex, "El expediente " + carpetaExpandir.getNombre(),
                                                  "abrir", "o");
                                      else
                                          this.manejarExcepcion(ex, "La carpeta " + carpetaExpandir.getNombre(),
                                                  "abrir", "a");}
          catch (InterruptedException ex) {ventana.errorGrave(ex.getMessage());}
    }

    private void manejarExcepcion(RemoteException ex, String articuloObjetoNombre, String accion, String letraGenero)
    {
        if (ex.getCause() instanceof ServiciosServidorException)
        {
            String msj= "";
            ServiciosServidorException e= (ServiciosServidorException) ex.getCause();
            switch (e.getCodigo())
            {
                case ServiciosServidorException.ERROR_ELEMENTO_ELIMINADO:
                    msj= articuloObjetoNombre + " no se puede " + accion + " porque\nha sido eliminad" +
                            letraGenero + " por otro usuario en la red.";
                    break;
                case ServiciosServidorException.ERROR_ELEMENTO_OCUPADO:
                    msj= articuloObjetoNombre + " no se puede " + accion + " porque\n está siendo " +
                            "utilizado por otro usuario en la red.";
                    break;
            }
            JOptionPane.showMessageDialog(ventana, msj, "Aviso", JOptionPane.WARNING_MESSAGE);
        }
        else
            ventana.errorRed(ex.getMessage());
    }

    private void seleccionarNodo(DefaultMutableTreeNode nodo, DefaultMutableTreeNode padre)
    {
        bloquearAlExpandir= false;
        if (nodo == null || padre.getChildCount() == 1)
        {
            TreePath pathPadre= new TreePath(padre.getPath());
            arbol.expandPath(pathPadre);
            arbol.setSelectionPath(pathPadre);
            ventana.actualizarBotonesPanelPrincipalYMostrarPopup(padre, false, false, null);
        }
        else
        {
            TreePath pathNodo= new TreePath(nodo.getPath());
            arbol.scrollPathToVisible(pathNodo);
            arbol.setSelectionPath(pathNodo);
            ventana.actualizarBotonesPanelPrincipalYMostrarPopup(nodo, false, false, null);
        }
        bloquearAlExpandir= true;
    }

    public void nuevoExpediente()
    {
        DialogoCrearExpediente dce= new DialogoCrearExpediente();
        Carpeta nueva= dce.hacerVisible(ventana);
        if (nueva != null)
        {
            try {
                DefaultMutableTreeNode padre= (DefaultMutableTreeNode) arbol.getLastSelectedPathComponent();
                if (padre != null)
                {
                    nucleo.setSistemaOcupado();
                    Object [] o= nucleo.crearCarpeta(nueva, (Carpeta) padre.getUserObject());
                    ppc.abrirExpedienteNuevo((Carpeta) o[1]);
                    semaforo.acquire();
                    DefaultMutableTreeNode nuevo= modificadorArbol.agregarCarpeta(padre, (Carpeta) o[0]);
                    this.seleccionarNodo(nuevo, padre);
                    semaforo.release();
                    nucleo.setSistemaLibre();
                }
                else
                    throw new ServiciosServidorException(ServiciosServidorException.ERROR_ELEMENTO_ELIMINADO);
            } catch (RemoteException ex) {nucleo.setSistemaLibre();
                                          this.manejarExcepcion(ex, "El expediente " + nueva.getNombre(), "crear", "o");}
              catch (InterruptedException ex) {ventana.errorGrave(ex.getMessage());}
        }
    }

    public void nuevaCarpeta()
    {
        DialogoCRCA dcrca= new DialogoCRCA(DialogoCRCA.TIPO_CREAR_CARPETA, "");
        String nombre= dcrca.hacerVisible(ventana);
        if (nombre != null)
        {
            Carpeta nueva= new Carpeta(new ArrayList<Long>());
            nueva.setNombre(nombre);
            nueva.setEsExpediente(false);
            try {
                DefaultMutableTreeNode padre= (DefaultMutableTreeNode) arbol.getLastSelectedPathComponent();
                if (padre != null)
                {
                    nucleo.setSistemaOcupado();
                    Object [] o= nucleo.crearCarpeta(nueva, (Carpeta) padre.getUserObject());
                    semaforo.acquire();
                    DefaultMutableTreeNode nuevo= modificadorArbol.agregarCarpeta(padre, (Carpeta) o[0]);
                    this.seleccionarNodo(nuevo, padre);
                    semaforo.release();
                    nucleo.setSistemaLibre();
                }
                else
                    throw new ServiciosServidorException(ServiciosServidorException.ERROR_ELEMENTO_ELIMINADO);
            } catch (RemoteException ex) {nucleo.setSistemaLibre();
                                          this.manejarExcepcion(ex, "La carpeta " + nueva.getNombre(), "crear", "a");}
              catch (InterruptedException ex) {ventana.errorGrave(ex.getMessage());}
        }
    }

    public void nuevoCliente()
    {
        DialogoCrearCliente dcc= new DialogoCrearCliente();
        Cliente nuevo= dcc.hacerVisible(ventana);
        if (nuevo != null)
        {
            try {
                DefaultMutableTreeNode padre= (DefaultMutableTreeNode) arbol.getLastSelectedPathComponent();
                if (padre != null)
                {
                    nucleo.setSistemaOcupado();
                    Object [] retorno= nucleo.crearCliente(nuevo, (Carpeta) padre.getUserObject());
                    ppc.abrirClienteNuevo((Cliente) retorno[1]);
                    semaforo.acquire();
                    DefaultMutableTreeNode agregado= modificadorArbol.agregarCliente(padre, (Carpeta) retorno[0]);
                    this.seleccionarNodo(agregado, padre);
                    semaforo.release();
                    nucleo.setSistemaLibre();
                }
                else
                    throw new ServiciosServidorException(ServiciosServidorException.ERROR_ELEMENTO_ELIMINADO);
            } catch (RemoteException ex) {nucleo.setSistemaLibre();
                                          this.manejarExcepcion(ex, "El cliente " + nuevo.toString(), "crear", "o");}
              catch (InterruptedException ex) {ventana.errorGrave(ex.getMessage());}
        }
    }

    public void nuevoArchivo()
    {
        FileFilter [] filtros= new FileFilter[0];
        Selector selector= new Selector(filtros, "Abrir archivo", true);
        File file= selector.hacerVisibleSelectorAbrir(ventana);
        if (file != null)
        {
            DialogoArchivo da= new DialogoArchivo(DialogoArchivo.TIPO_TRANSFERIR);
            DefaultMutableTreeNode padre= (DefaultMutableTreeNode) arbol.getLastSelectedPathComponent();
            try {
                if (padre != null)
                {
                    nucleo.setSistemaOcupado();
                    da.hacerVisible(ventana);
                    Carpeta padreExpandido= nucleo.crearArchivo(file, (Carpeta) padre.getUserObject());
                    semaforo.acquire();
                    DefaultMutableTreeNode nuevo= modificadorArbol.agregarArchivo(padre, padreExpandido);
                    this.seleccionarNodo(nuevo, padre);
                    semaforo.release();
                    da.ocultar();
                    nucleo.setSistemaLibre();
                }
                else
                    throw new ServiciosServidorException(ServiciosServidorException.ERROR_ELEMENTO_ELIMINADO);
            } catch (RemoteException ex) {da.ocultar();
                                          nucleo.setSistemaLibre();
                                          this.manejarExcepcion(ex, "El archivo " + file.getName(), "crear", "o");}
              catch (IOException ex) {ventana.errorRed(ex.getMessage());}
              catch (InterruptedException ex) {ventana.errorGrave(ex.getMessage());}
        }
    }

    public void cortar()
    {
        nucleo.setSistemaOcupado();
        DefaultMutableTreeNode nodo= (DefaultMutableTreeNode) arbol.getLastSelectedPathComponent();
        elementoPegar= nodo.getUserObject();
        padreViejo= (Carpeta) ((DefaultMutableTreeNode) nodo.getParent()).getUserObject();
        operacion= CORTAR;
        nucleo.setSistemaLibre();
    }

    public void copiar()
    {
        nucleo.setSistemaOcupado();
        DefaultMutableTreeNode nodo= (DefaultMutableTreeNode) arbol.getLastSelectedPathComponent();
        elementoPegar= nodo.getUserObject();
        padreViejo= null;
        operacion= COPIAR;
        nucleo.setSistemaLibre();
    }

    public void pegar()
    {
        String msj= "No es posible colocar una carpeta dentro de un expediente.\nUn expediente puede contener solamente " +
                "clientes y archivos.";
        Carpeta padreActualizado;
        DefaultMutableTreeNode nodoPadreNuevo= (DefaultMutableTreeNode) arbol.getLastSelectedPathComponent();
        TreePath pathPadre= new TreePath(nodoPadreNuevo.getPath());
        Carpeta padreNuevo= (Carpeta) nodoPadreNuevo.getUserObject();
        if (elementoPegar == null)
            return;
        try {
            if (elementoPegar instanceof Carpeta)
            {
                if (padreNuevo.esExpediente())
                {
                    JOptionPane.showMessageDialog(ventana, msj, "Pegar", JOptionPane.INFORMATION_MESSAGE);
                    return;
                }
                if (operacion == COPIAR)
                {
                    padreActualizado= nucleo.copiarCarpeta((Carpeta) elementoPegar, padreNuevo);
                    this.actualizarCarpeta(padreActualizado, InterfazServiciosServidor.AGREGAR_CARPETA);
                }
                else
                {
                    padreActualizado= nucleo.cortarCarpeta((Carpeta) elementoPegar, padreNuevo, padreViejo);
                    this.cortarObjeto(elementoPegar, padreViejo, padreActualizado);
                }
                if (arbol.isCollapsed(pathPadre))
                    arbol.expandPath(pathPadre);
                return;
            }
            if (elementoPegar instanceof Cliente)
            {
                if (operacion == COPIAR)
                {
                    padreActualizado= nucleo.copiarCliente((Cliente) elementoPegar, padreNuevo);
                    this.actualizarCarpeta(padreActualizado, InterfazServiciosServidor.AGREGAR_CLIENTE);
                }
                else
                {
                    padreActualizado= nucleo.cortarCliente((Cliente) elementoPegar, padreNuevo, padreViejo);
                    this.cortarObjeto(elementoPegar, padreViejo, padreActualizado);
                }
            }
            else
            {
                if (operacion == COPIAR)
                {
                    padreActualizado= nucleo.copiarArchivo((Archivo) elementoPegar, padreNuevo);
                    this.actualizarCarpeta(padreActualizado, InterfazServiciosServidor.AGREGAR_ARCHIVO);
                }
                else
                {
                    padreActualizado= nucleo.cortarArchivo((Archivo) elementoPegar, padreNuevo, padreViejo);
                    this.cortarObjeto(elementoPegar, padreViejo, padreActualizado);
                }
            }
            if (arbol.isCollapsed(pathPadre))
                arbol.expandPath(pathPadre);
        } catch (RemoteException ex) {this.manejarExcepcion(ex, "El elemento " + elementoPegar.toString(), "mover", "o");}
    }

    public void eliminar()
    {
        DefaultMutableTreeNode nodo= (DefaultMutableTreeNode) arbol.getLastSelectedPathComponent();
        if (nodo != null)
        {
            DefaultMutableTreeNode padre= (DefaultMutableTreeNode) nodo.getParent();
            Object elemento= nodo.getUserObject();
            if (elemento instanceof Carpeta)
                this.eliminarCarpeta(nodo, padre);
            else
            {
                if (elemento instanceof Cliente)
                    this.eliminarCliente(nodo, padre);
                else
                    this.eliminarArchivo(nodo, padre);
            }
        }
    }

    private void eliminarCarpeta(DefaultMutableTreeNode nodoEliminar, DefaultMutableTreeNode padre)
    {
        Carpeta carpetaEliminar= (Carpeta) nodoEliminar.getUserObject();
        Carpeta carpetaPadre= (Carpeta) padre.getUserObject();
        String falla, msj, fin;
        if (carpetaEliminar.esExpediente())
        {
            falla= "El expediente seleccionado no se puede eliminar ya que uno o más elementos que ella contiene\n" +
                    "están siendo utilizados por usted u otro usuario en la red.";
            msj= "¿Seguro desea eliminar el expediente " + carpetaEliminar.getNombre() + " y todo su contenido?";
            fin= "El expediente seleccionado ha sido eliminado.";
        }
        else
        {
            falla= "La carpeta seleccionada no se puede eliminar ya que uno o más elementos que ella contiene\n" +
                    "están siendo utilizados por usted u otro usuario en la red.";
            msj= "¿Seguro desea eliminar la carpeta " + carpetaEliminar.getNombre() + " y todo su contenido?";
            fin= "La carpeta seleccionada ha sido eliminada.";
        }
        int resp= JOptionPane.showConfirmDialog(ventana, msj, "Eliminar", JOptionPane.YES_NO_OPTION,
                JOptionPane.QUESTION_MESSAGE);
        if (resp == JOptionPane.YES_OPTION)
        {
            try {
                List<Cliente> eliminados= nucleo.eliminarCarpeta(carpetaEliminar, carpetaPadre);
                if (eliminados != null)
                {
                    semaforo.acquire();
                    nucleo.setSistemaOcupado();
                    modificadorArbol.eliminarNodo(nodoEliminar);
                    semaforo.release();
                    ventana.actualizarBotonesPanelPrincipalYMostrarPopup(null, false, false, null);
                    ppc.cerrarPestaniasClientesEliminados(eliminados);
                    nucleo.setSistemaLibre();
                    JOptionPane.showMessageDialog(ventana, fin, "Eliminar", JOptionPane.INFORMATION_MESSAGE);
                }
                else
                    JOptionPane.showMessageDialog(ventana, falla, "Eliminar", JOptionPane.WARNING_MESSAGE);
            } catch (RemoteException ex) {ventana.errorRed(ex.getMessage());}
              catch (InterruptedException ex) {ventana.errorGrave(ex.getMessage());}
        }
    }

    private void eliminarCliente(DefaultMutableTreeNode nodoEliminar, DefaultMutableTreeNode padre)
    {
        Cliente clienteEliminar= (Cliente) nodoEliminar.getUserObject();
        Carpeta carpetaPadre= (Carpeta) padre.getUserObject();
        String falla= "El cliente seleccionado no se puede eliminar porque está siendo\nutilizado por otro usuario " +
                "en la red.";
        String msj= "¿Seguro desea eliminar el cliente " + clienteEliminar.toString() + "?";
        int resp= JOptionPane.showConfirmDialog(ventana, msj, "Eliminar", JOptionPane.YES_NO_OPTION,
                JOptionPane.QUESTION_MESSAGE);
        if (resp == JOptionPane.YES_OPTION)
        {
            try {
                if (nucleo.eliminarCliente(clienteEliminar, carpetaPadre))
                {
                    semaforo.acquire();
                    nucleo.setSistemaOcupado();
                    modificadorArbol.eliminarNodo(nodoEliminar);
                    semaforo.release();
                    ventana.actualizarBotonesPanelPrincipalYMostrarPopup(null, false, false, null);
                    ppc.cerrarPestaniaClienteEliminado(clienteEliminar);
                    nucleo.setSistemaLibre();
                    JOptionPane.showMessageDialog(ventana, "El cliente seleccionado ha sido eliminado.",
                            "Eliminar", JOptionPane.INFORMATION_MESSAGE);
                }
                else
                    JOptionPane.showMessageDialog(ventana, falla, "Eliminar", JOptionPane.WARNING_MESSAGE);
            } catch (RemoteException ex) {ventana.errorRed(ex.getMessage());}
              catch (InterruptedException ex) {ventana.errorGrave(ex.getMessage());}
        }
    }

    private void eliminarArchivo(DefaultMutableTreeNode nodoEliminar, DefaultMutableTreeNode padre)
    {
        Archivo archivoEliminar= (Archivo) nodoEliminar.getUserObject();
        Carpeta carpetaPadre= (Carpeta) padre.getUserObject();
        String falla= "El archivo seleccionado no se puede eliminar porque está siendo utilizado\npor usted u otro " +
                "usuario en la red.\n\nNota: para evitar fallas en aplicaciones externas, no se permite eliminar\n" +
                "un archivo que se encuentre en uso.";
        String msj= "¿Seguro desea eliminar el archivo " + archivoEliminar.toString() + "?";
        int resp= JOptionPane.showConfirmDialog(ventana, msj, "Eliminar", JOptionPane.YES_NO_OPTION,
                JOptionPane.QUESTION_MESSAGE);
        if (resp == JOptionPane.YES_OPTION)
        {
            nucleo.setSistemaOcupado();
            DialogoArchivo da= new DialogoArchivo(DialogoArchivo.TIPO_ELIMINAR);
            da.hacerVisible(ventana);
            try {
                if (nucleo.eliminarArchivo(archivoEliminar, carpetaPadre))
                {
                    semaforo.acquire();
                    modificadorArbol.eliminarNodo(nodoEliminar);
                    semaforo.release();
                    ventana.actualizarBotonesPanelPrincipalYMostrarPopup(null, false, false, null);
                    da.ocultar();
                    nucleo.setSistemaLibre();
                    JOptionPane.showMessageDialog(ventana, "El archivo seleccionado ha sido eliminado.",
                            "Eliminar", JOptionPane.INFORMATION_MESSAGE);
                }
                else
                {
                    da.ocultar();
                    nucleo.setSistemaLibre();
                    JOptionPane.showMessageDialog(ventana, falla, "Eliminar", JOptionPane.WARNING_MESSAGE);
                }
            } catch (RemoteException ex) {da.ocultar();
                                          ventana.errorRed(ex.getMessage());}
              catch (InterruptedException ex) {ventana.errorGrave(ex.getMessage());}
        }
    }

    public void renombrar()
    {
        DefaultMutableTreeNode nodo= (DefaultMutableTreeNode) arbol.getLastSelectedPathComponent();
        if (nodo != null)
        {
            if (nodo.getUserObject() instanceof Carpeta)
            {
                Carpeta c= (Carpeta) nodo.getUserObject();
                try {
                    this.renombrarCarpeta(nodo);
                } catch (RemoteException ex) {this.manejarExcepcion(ex, "La carpeta " + c.getNombre(), "renombrar", "a");}
            }
            else
            {
                Archivo a= (Archivo) nodo.getUserObject();
                if (nucleo.archivoAbierto(a))
                {
                    paac.seleccionarEnLista(a);
                    JOptionPane.showMessageDialog(ventana, "No se puede renombrar el archivo seleccionado " +
                            "porque está siendo utilizado.", "Renombrar", JOptionPane.WARNING_MESSAGE);
                }
                else
                {
                    try {
                        this.renombrarArchivo(nodo);
                    } catch (RemoteException ex) {this.manejarExcepcion(ex, "El archivo " + a.getNombre(), "renombrar", "o");}
                }
            }
        }
    }

    private void renombrarCarpeta(DefaultMutableTreeNode aRenombrar) throws RemoteException
    {
        DefaultMutableTreeNode padre= (DefaultMutableTreeNode) aRenombrar.getParent();
        Carpeta carpetaRenombrar= (Carpeta) aRenombrar.getUserObject();
        DialogoCRCA dcrca= new DialogoCRCA(DialogoCRCA.TIPO_RENOMBRAR_CARPETA, carpetaRenombrar.getNombre());
        String nuevoNombre= dcrca.hacerVisible(ventana);
        if (nuevoNombre != null)
        {
            carpetaRenombrar.setNombre(nuevoNombre);
            Carpeta carpetaPadre= nucleo.guardarCarpeta(carpetaRenombrar);
            try {
                semaforo.acquire();
                nucleo.setSistemaOcupado();
                modificadorArbol.organizarCarpetas(padre, carpetaPadre);
                this.seleccionarNodo(aRenombrar, padre);
                nucleo.setSistemaLibre();
                semaforo.release();
            } catch (InterruptedException ex) {ventana.errorGrave(ex.getMessage());}
        }
    }

    private void renombrarArchivo(DefaultMutableTreeNode aRenombrar) throws RemoteException
    {
        DefaultMutableTreeNode padre= (DefaultMutableTreeNode) aRenombrar.getParent();
        Archivo archivoRenombrar= (Archivo) aRenombrar.getUserObject();
        DialogoCRCA dcrca= new DialogoCRCA(DialogoCRCA.TIPO_RENOMBRAR_ARCHIVO, archivoRenombrar.getNombre());
        String nuevoNombre= dcrca.hacerVisible(ventana);
        if (nuevoNombre != null)
        {
            archivoRenombrar.setNombre(nuevoNombre);
            Carpeta carpetaPadre= nucleo.cambiarNombreArchivo(archivoRenombrar, (Carpeta) padre.getUserObject());
            try {
                semaforo.acquire();
                nucleo.setSistemaOcupado();
                modificadorArbol.organizarArchivos(padre, carpetaPadre);
                this.seleccionarNodo(aRenombrar, padre);
                nucleo.setSistemaLibre();
                semaforo.release();
            } catch (InterruptedException ex) {ventana.errorGrave(ex.getMessage());}
        }
    }

    public void buscar(ItemBusqueda item)
    {
        String msj= "No se ha podido encontrar el elemento.\nEl mismo ha sido eliminado por otro usuario en la red.";
        Object buscado= null;
        switch (item.getTipoBusqueda())
        {
            case DialogoBusqueda.BUSCAR_CARPETA:
            case DialogoBusqueda.BUSCAR_EXPEDIENTE_CARATULA:
            case DialogoBusqueda.BUSCAR_EXPEDIENTE_ESTADO:
            case DialogoBusqueda.BUSCAR_EXPEDIENTE_INSTANCIA:
            case DialogoBusqueda.BUSCAR_EXPEDIENTE_JUZGADO:
            case DialogoBusqueda.BUSCAR_EXPEDIENTE_SECRETARIA:
            case DialogoBusqueda.BUSCAR_EXPEDIENTE_TIPO:
                buscado= new Carpeta(item.obtenerCopiaRuta());
                break;
            case DialogoBusqueda.BUSCAR_ARCHIVO:
                buscado= new Archivo(item.obtenerCopiaRuta());
                break;
            case DialogoBusqueda.BUSCAR_CLIENTE_APELLIDO:
            case DialogoBusqueda.BUSCAR_CLIENTE_NOMBRE:
            case DialogoBusqueda.BUSCAR_CLIENTE_DNI:
                buscado= new Cliente(item.obtenerCopiaRuta());
                break;
        }
        nucleo.setSistemaOcupado();
        DefaultMutableTreeNode resultado= this.buscarExpandiendoRuta(raiz, buscado);
        if (resultado == null)
            JOptionPane.showMessageDialog(ventana, msj, "Buscar", JOptionPane.WARNING_MESSAGE);
        else
        {
            DefaultMutableTreeNode padre= (DefaultMutableTreeNode) resultado.getParent();
            this.seleccionarNodo(resultado, padre); //No importa si el padre es nulo porque resultado nunca es nulo.
        }
        nucleo.setSistemaLibre();
    }

    //Retorna nulo si el elemento y otros componentes de la ruta fueron eliminados.
    private DefaultMutableTreeNode buscarExpandiendoRuta(DefaultMutableTreeNode inicio, Object buscado)
    {
        Object elementoNodo= inicio.getUserObject();
        if (elementoNodo.equals(buscado))
            return inicio;
        if (elementoNodo instanceof Carpeta && ((Identificable) buscado).estaEnRuta(((Carpeta) elementoNodo).obtenerId()))
        {
            TreePath path= new TreePath(inicio.getPath());
            if (arbol.isCollapsed(path))
                arbol.expandPath(path);
            Enumeration hijos= inicio.children();
            while (hijos.hasMoreElements())
            {
                DefaultMutableTreeNode retorno= this.buscarExpandiendoRuta((DefaultMutableTreeNode) hijos.nextElement(),
                        buscado);
                if (retorno != null)
                    return retorno;
            }
        }
        return null;
    }

    //Retorna nulo si el objeto buscado no está en el subárbol.
    private DefaultMutableTreeNode buscarNodo(DefaultMutableTreeNode inicio, Object elementoBuscar)
    {
        if (inicio.getUserObject().equals(elementoBuscar))
            return inicio;
        Enumeration hijos= inicio.children();
        while (hijos.hasMoreElements())
        {
            DefaultMutableTreeNode nodoBuscado= this.buscarNodo((DefaultMutableTreeNode) hijos.nextElement(),
                    elementoBuscar);
            if (nodoBuscado != null)
                return nodoBuscado;
        }
        return null;
    }

    private void realizarActualizacion(Carpeta c, DefaultMutableTreeNode padre, int operacion)
    {
        switch (operacion)
        {
            case InterfazServiciosServidor.AGREGAR_CLIENTE: modificadorArbol.agregarCliente(padre, c); break;
            case InterfazServiciosServidor.AGREGAR_CARPETA: modificadorArbol.agregarCarpeta(padre, c); break;
            case InterfazServiciosServidor.AGREGAR_ARCHIVO: modificadorArbol.agregarArchivo(padre, c); break;
            case InterfazServiciosServidor.ORDENAR_CLIENTES: modificadorArbol.organizarClientes(padre, c); break;
            case InterfazServiciosServidor.ORDENAR_CARPETAS: modificadorArbol.organizarCarpetas(padre, c); break;
            case InterfazServiciosServidor.ORDENAR_ARCHIVOS: modificadorArbol.organizarArchivos(padre, c); break;
        }
    }

    @Override
    public void actualizarCarpeta(Carpeta c, int operacion) {
        try {
            semaforo.acquire();
            nucleo.setSistemaOcupado();
            DefaultMutableTreeNode nodoBuscado= this.buscarNodo(raiz, c);
            if (nodoBuscado != null)
            {
                TreePath path= new TreePath(nodoBuscado.getPath());
                if (arbol.isExpanded(path))
                    this.realizarActualizacion(c, nodoBuscado, operacion);
                else
                {
                    if (nodoBuscado.isLeaf())
                        modificadorArbol.agregarNodoVacio(nodoBuscado);
                }
                if (arbol.isSelectionEmpty())
                    ventana.actualizarBotonesPanelPrincipalYMostrarPopup(null, false, false, null);
            }
            nucleo.setSistemaLibre();
            semaforo.release();
        } catch (InterruptedException ex) {ventana.errorGrave(ex.getMessage());}
    }

    @Override
    public void quitarDeCarpeta(Carpeta c, Object o) {
        try {
            semaforo.acquire();
            nucleo.setSistemaOcupado();
            DefaultMutableTreeNode nodoBuscado= this.buscarNodo(raiz, c);
            if (nodoBuscado != null)
            {
                TreePath path= new TreePath(nodoBuscado.getPath());
                if (arbol.isExpanded(path))
                {
                    DefaultMutableTreeNode nodoQuitar= this.buscarNodo(nodoBuscado, o);
                    if (nodoQuitar != null)
                    {
                        modificadorArbol.eliminarNodo(nodoQuitar);
                        DefaultMutableTreeNode nodoSeleccionado=
                                (DefaultMutableTreeNode) arbol.getLastSelectedPathComponent();
                        ventana.actualizarBotonesPanelPrincipalYMostrarPopup(nodoSeleccionado, false, false, null);
                    }
                }
                else
                {
                    if (!c.poseeHijos())
                    {
                        DefaultMutableTreeNode nodoVacio= (DefaultMutableTreeNode) nodoBuscado.getChildAt(0);
                        modificadorArbol.eliminarNodo(nodoVacio);
                    }
                }
            }
            nucleo.setSistemaLibre();
            semaforo.release();
        } catch (InterruptedException ex) {ventana.errorGrave(ex.getMessage());}
    }

    @Override
    public void cortarObjeto(Object o, Carpeta vieja, Carpeta nueva) {
        this.quitarDeCarpeta(vieja, o);
        if (o instanceof Carpeta)
            this.actualizarCarpeta(nueva, InterfazServiciosServidor.AGREGAR_CARPETA);
        else
        {
            if (o instanceof Cliente)
                this.actualizarCarpeta(nueva, InterfazServiciosServidor.AGREGAR_CLIENTE);
            else
                this.actualizarCarpeta(nueva, InterfazServiciosServidor.AGREGAR_ARCHIVO);
        }
    }

    @Override
    public void archivoModificado(Archivo mod) {
        paac.archivoModificado(mod);
    }
}
